2016/09/10

Recent entries from same category

  1. Go 言語プログラミングエッセンスという本を書きました。
  2. errors.Join が入った。
  3. unsafe.StringData、unsafe.String、unsafe.SliceData が入った。
  4. Re: Go言語で画像ファイルか確認してみる
  5. net/url に JoinPath が入った。

「みんなのGo言語」が本日発売となりました。

現在、プログラミング言語のカテゴリで1位の様です。めでたい。

みんなのGo言語

僕も執筆に参加させて頂いたので興味ある方はぜひ読んで欲しいです。

さて最近の僕がGo言語で何を書いていたかというと
GitHub - mattn/go-slim: Slim Template Engine for golang

Rslim template engine for golang

https://github.com/mattn/go-slim

slim template の golang 版です。忙しくてまだ完成はしていないんですが、ちょっとした物であれば使えるレベルまで出来ていると思っています。haml を golang で実装している物はいくらかあったのですが、僕は haml よりも slim が好きなので何も迷わず実装しました。

doctype 5
html lang="ja"
  head
    meta charset="UTF-8"
    title
  body
    ul
    - for x in foo
      li = x

こんな slim のテンプレートを用意して

tmpl, err := slim.ParseFile("template.slim")
if err != nil {
    t.Fatal(err)
}
err = tmpl.Execute(os.Stdout, slim.Values{
    "foo": []string{"foo""bar""baz"},
})

テンプレートを読み込んで値を渡しながら Execute を呼び出します。すると

<!doctype html>
<html lang="ja">
  <head>
    <meta charset="UTF-8"/>
    <title>
    </title>
  </head>
  <body>
    <ul>
      <li>foo</li>
      <li>bar</li>
      <li>baz</li>
    </ul>
  </body>
</html>

綺麗な HTML が生成されます。slim 内での式にも対応していて for in 文だけでなく

= foo[0] + foo[1].Bar[0]

式も書けるし以下の様なコードに対して

:= make(map[string]string)
m["baz"= "Baz!"

type Baz struct {
    Fuga string
}
var buf bytes.Buffer
err = tmpl.Execute(&buf, Values{
    "foo"struct {
        Baz []Baz
    }{
        Baz: []Baz{
            {Fuga: "hello"},
            {Fuga: "world"},
            {Fuga: "golang"},
        },
    },
    "bar": m,
})

構造体や map を参照してテンプレートから扱う事も出来ます。

= bar.baz
- for x in foo.Baz
    p = x.Fuga

ruby を内部で実行する代わりに slim 用の専用のインタプリタ言語を作っています。はじめは anko を埋め込もうと思ったのですが高機能すぎるので文法の小さい物にしています。割と綺麗に書けました。おそらくですが他のテンプレートエンジンに使いまわしたり、「プログラミング言語の実装ちょっと興味ある」という方には良い教材になると思います。vm というフォルダだけ持っていけば他のプロダクトにも埋め込められるはずです。

面白いところでは for in 文の右辺に配列だけでなく channel を指定できる様にしてあります。

ch := make(chan string)
go func() {
    for _, a := range []string{"foo""bar""baz"} {
        ch <- a
    }
    close(ch)
}()

var buf bytes.Buffer
err = tmpl.Execute(&buf, Values{
    "foo": ch,
})
こんな風に chan をテンプレートに渡して ul
  - for x in foo
    li = x
slim から呼び出すと <ul>
  <li>foo</li>
  <li>bar</li>
  <li>baz</li>
</ul>

ループを回してくれます。実用的かどうかなんて関係ないです。面白ければいいんです。

まだやりかけというだけあって slim から使える関数は trim, to_upper, to_lower, split 程度しかありませんが、適当に時間を見つけて作って行きたいと思います。

Posted at by